#include "descriptors.h"


///////////////  GDT stuff

GDT_entry gdt[GDT_ENTRIES];
GDTR gdtr;

void init_GDT() {
  // these are all a bitch, but we gotta set them by hand
  // zero entry. must be here by definition
  gdt[0].limit_low   = 0;
  gdt[0].base_low    = 0;
  gdt[0].base_middle = 0;
  gdt[0].access      = 0;
  gdt[0].granularity = 0;
  gdt[0].base_high   = 0;
  // set kernel CS
  gdt[1].limit_low   = 0xFFFF;
  gdt[1].base_low    = 0x0000;
  gdt[1].base_middle = 0x00;
  gdt[1].access      = 0x98;
  gdt[1].granularity = 0xCF;
  gdt[1].base_high   = 0x00;
  // set kernel DS
  gdt[2].limit_low   = 0xFFFF;
  gdt[2].base_low    = 0x0000;
  gdt[2].base_middle = 0x00;
  gdt[2].access      = 0x92;
  gdt[2].granularity = 0xCF;
  gdt[2].base_high   = 0x00;
  // set user CS
  gdt[3].limit_low   = 0xFFFF;
  gdt[3].base_low    = 0x0000;
  gdt[3].base_middle = 0x00;
  gdt[3].access      = 0x98;
  gdt[3].granularity = 0xCF;
  gdt[3].base_high   = 0x00;
  // set user DS
  gdt[4].limit_low   = 0xFFFF;
  gdt[4].base_low    = 0x0000;
  gdt[4].base_middle = 0x00;
  gdt[4].access      = 0x92;
  gdt[4].granularity = 0xCF;
  gdt[4].base_high   = 0x00;

  gdtr.limit = sizeof(GDT_entry) * GDT_ENTRIES;
  gdtr.base = (u32)&gdt;
  flush_gdt((u32)&gdtr);
}



///////////////  IDT stuff

IDTR idtr;
IDT_entry idt[MAX_INTERRUPTS];
static void idt_set_gate(int, u16, u8, u32);

void init_IDT()  {
  idt_set_gate(0, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_0);
  idt_set_gate(1, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_1);
  idt_set_gate(2, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_2);
  idt_set_gate(3, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_3);
  idt_set_gate(4, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_4);
  idt_set_gate(5, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_5);
  idt_set_gate(6, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_6);
  idt_set_gate(7, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_7);
  idt_set_gate(8, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_8);
  idt_set_gate(9, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_9);
  idt_set_gate(10, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_10);
  idt_set_gate(11, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_11);
  idt_set_gate(12, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_12);
  idt_set_gate(13, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_13);
  idt_set_gate(14, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_14);
  idt_set_gate(15, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_15);
  idt_set_gate(16, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_16);
  idt_set_gate(17, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_17);
  idt_set_gate(18, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_18);
  idt_set_gate(19, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_19);
  idt_set_gate(20, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_20);
  idt_set_gate(21, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_21);
  idt_set_gate(22, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_22);
  idt_set_gate(23, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_23);
  idt_set_gate(24, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_24);
  idt_set_gate(25, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_25);
  idt_set_gate(26, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_26);
  idt_set_gate(27, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_27);
  idt_set_gate(28, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_28);
  idt_set_gate(29, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_29);
  idt_set_gate(30, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_30);
  idt_set_gate(31, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_31);
  idt_set_gate(32, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_32);
  idt_set_gate(33, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_33);
  idt_set_gate(34, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_34);
  idt_set_gate(35, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_35);
  idt_set_gate(36, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_36);
  idt_set_gate(37, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_37);
  idt_set_gate(38, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_38);
  idt_set_gate(39, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_39);
  idt_set_gate(40, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_40);
  idt_set_gate(41, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_41);
  idt_set_gate(42, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_42);
  idt_set_gate(43, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_43);
  idt_set_gate(44, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_44);
  idt_set_gate(45, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_45);
  idt_set_gate(46, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_46);
  idt_set_gate(47, KERNEL_CS, INTERRUPT_FLAGS, (u32)isr_stub_47);

  idtr.limit = sizeof(IDT_entry) * MAX_INTERRUPTS - 1;
  idtr.offset = (u32)(&idt);
  load_IDT(((u32)&idtr));

  
}

static void idt_set_gate(int num, u16 selector, u8 flags, u32 handler) {
  idt[num].zero = 0;
  idt[num].flags = flags;
  idt[num].selector = selector;
  idt[num].base_lo = handler & 0xFFFF;
  idt[num].base_hi = (handler >> 16) & 0xFFFF;
}
